package com.hoppinzq.service.jar;


import com.hoppinzq.service.aop.annotation.ApiMapping;
import com.hoppinzq.service.aop.annotation.ApiServiceMapping;
import com.hoppinzq.service.aop.annotation.RateLimit;
import com.hoppinzq.service.bean.*;
import com.hoppinzq.service.cache.SSHCache;
import com.hoppinzq.service.config.WebSocketProcess;
import com.hoppinzq.service.dao.JarServiceMapper;
import com.hoppinzq.service.dao.LogDao;
import com.hoppinzq.service.monitor.FileProgressMonitor;
import com.hoppinzq.service.util.RedisUtils;
import com.hoppinzq.service.util.UUIDUtil;
import com.jcraft.jsch.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.web.multipart.MultipartFile;

import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.management.*;
import java.util.*;

@ApiServiceMapping(title = "jar服务", description = "jar服务",roleType = ApiServiceMapping.RoleType.RIGHT)
public class JarService {
    @Autowired
    private WebSocketProcess webSocketProcess;
    @Autowired
    private LogDao logDao;
    @Autowired
    private JarServiceMapper jarServiceMapper;
    @Autowired
    private RedisUtils redisUtils;

    @ApiMapping(value = "isLogin", title = "ssh状态", description = "ssh是否在登录状态")
    public boolean login(String sessionId){
        Map<String, SSHBean> sshMap=SSHCache.sshMap;
        if(sshMap.containsKey(sessionId)){
            SSHBean sshBean=sshMap.get(sessionId);
            return sshBean.isLogin();
        }else{
            return false;
        }
    }

    @ApiMapping(value = "queryAllJar", title = "查询jar包服务", description = "查询jar包服务")
    public List queryAllJar(){
        Map map=new HashMap();
        List jars=new ArrayList();
        if(redisUtils.hasKey("manager:all_jar")){
            jars=(List)redisUtils.get("manager:all_jar");
        }else{
            jars=jarServiceMapper.selectByMap(map);
            redisUtils.set("manager:all_jar",jars);
        }
        return jars;
    }

    @RateLimit(limit = 1,timeout = 25000)
    @ApiMapping(value = "flashAllJar", title = "刷新jar包服务", description = "刷新jar包服务")
    public List flashAllJar() throws Exception {
        Map map=new HashMap();
        List<JarServiceBean> list= jarServiceMapper.selectByMap(map);
        for (JarServiceBean jar:list) {
            flashJar(jar);
        }
        redisUtils.set("manager:last_update_jar",new Date());
        return list;
    }

    @ApiMapping(value = "queryLastFlashDate", title = "查询上次更新时间", description = "查询上次更新时间")
    public Object queryLastFlashDate(String key){
        return redisUtils.get(key);
    }

    private JarServiceBean flashJar(JarServiceBean jarServiceBean) throws Exception {
        if(jarServiceBean!=null){
            Boolean isChange=false;
            int pid=jarServiceBean.getPid();
            String jarName=jarServiceBean.getJar_name();
            if(pid!=0){
                String strPid=getCommand("ps -ef | grep pid "+pid);
                if("error".equals(strPid)||"".equals(strPid)){
                    jarServiceBean.setState(0);
                    isChange=true;
                    redisUtils.del("manager:last_jar_class_"+jarServiceBean.getId());
                }
                String strJC=getCommand("ps -ef|grep "+jarName+".jar|grep -v grep|awk '{print $2}'");
                if(strJC==null||"".equals(strJC)||"error".equals(strJC)){}else{
                    strJC=strJC.split(System.lineSeparator())[0];
                    jarServiceBean.setPid(Integer.parseInt(strJC));
                    jarServiceBean.setState(1);
                    isChange=true;
                }
                if(isChange){
                    redisUtils.del("manager:all_jar");
                    jarServiceMapper.updateById(jarServiceBean);
                }
            }
        }
        return jarServiceBean;
    }

    @ApiMapping(value = "flashJarById", title = "通过id刷新jar包服务", description = "通过id刷新jar包服务")
    public JarServiceBean flashJarById(String id) throws Exception {
        JarServiceBean jarServiceBean=jarServiceMapper.selectById(id);
        flashJar(jarServiceBean);
        return jarServiceBean;
    }

    @ApiMapping(value = "cleanSession", title = "清理会话", description = "清理会话")
    public int cleanSSHSession(){
        Map<String, SSHBean> sshMap=SSHCache.sshMap;
        int index=0;
        for(Map.Entry<String, SSHBean> entry:sshMap.entrySet()){
            index++;
            SSHBean sshBean=entry.getValue();
            sshBean.closeSession();
            sshMap.remove(entry.getKey());
            System.out.println("id:"+entry.getKey()+"，对应的会话已结束");
        }
        return index;
    }

    @ApiMapping(value = "closeSocket", title = "关闭socket连接", description = "关闭socket连接")
    public boolean closeSocket(String userno,String sessionId){
       cleanSessionById(sessionId);
       return webSocketProcess.closeSocket(userno);
    }

    @ApiMapping(value = "cleanSessionById", title = "关闭指定sessionID的会话", description = "清理指定SessionID的会话，一般当websocket关闭时调用，关闭为websocket提供服务的会话")
    public int cleanSessionById(String sessionId){
        Map<String, SSHBean> sshMap=SSHCache.sshMap;
        if(sshMap.containsKey(sessionId)){
            SSHBean sshBean=sshMap.get(sessionId);
            sshBean.closeSession();
            return 1;
        }else{
            return 0;
        }
    }

    @ApiMapping(value = "checkServiceName", title = "检测服务名是否被使用", description = "检测服务名是否被使用")
    public String checkServiceName(String name) throws Exception {
        Map<String, Object> queryPort = new HashMap<>();
        queryPort.put("service_name", name);
        List<JarServiceBean> jars = jarServiceMapper.selectByMap(queryPort);
        if (jars.size() != 0){
            throw new RuntimeException("该服务名已被使用");
        }
        return "服务名可以使用";
    }

    @ApiMapping(value = "checkPort", title = "检测端口号是否被使用", description = "检测端口号是否被使用")
    public String checkPort(int port) throws Exception {
        if(port>50000){
            throw new RuntimeException("该端口号太大");
        }
        if(port<8000){
            throw new RuntimeException("该端口号太小");
        }
        Map<String, Object> queryPort = new HashMap<>();
        queryPort.put("port", port);
        List<JarServiceBean> jars = jarServiceMapper.selectByMap(queryPort);
        if (jars.size() != 0){
            throw new RuntimeException("该端口号已被使用");
        }
        String isPort=getCommand("lsof -i:"+port);
        if(isPort!=null&&!"".equals(isPort)){
            throw new RuntimeException("该端口号已被使用");
        }
        return "端口号可以使用";
    }

    @ApiMapping(value = "jarfile", title = "jar包上传", description = "上传jar包并生成文件",type = ApiMapping.Type.POST)
    public void jarFile(MultipartFile file, String projectName, String ms,String version,int port ,String userno,Boolean isJMX,Boolean isDebugger) throws Exception {
        //检查端口号情况
        checkPort(port);
        SSHBean sshBean= new SSHBean();
        sshBean.sshRemoteLogin();
        Session sshSession=sshBean.getSession();
        SSHCache.sshMap.put(UUIDUtil.getUUID(),sshBean);
        ChannelSftp channelSftp = (ChannelSftp) sshSession.openChannel("sftp");

        // 远程连接
        channelSftp.connect();
        //判断是否有文件夹
        String remoteDirPath = "/home/hoppinzq/";
        Vector<ChannelSftp.LsEntry> lsEntries = channelSftp.ls(remoteDirPath);
        boolean folderExists = false;
        for (ChannelSftp.LsEntry entry : lsEntries) {
            if (entry.getFilename().equals(projectName)) {
                folderExists = true;
                break;
            }
        }
        if (folderExists) {
            //文件夹存在，不进行任何操作
        } else {
            //文件夹不存在，新建文件夹
            channelSftp.mkdir(remoteDirPath+projectName);
        }
        String jarName=file.getOriginalFilename();
        String jarFileName=jarName.substring(0,jarName.lastIndexOf(".jar"));
        String dst = remoteDirPath+projectName+"/"+jarName; // 目标文件名
        InputStream inputStream = file.getInputStream();
        long fileSize = file.getSize();
        webSocketProcess.setMark("file_upload");
        //jar包存储
        channelSftp.put(inputStream, dst, new FileProgressMonitor(fileSize,webSocketProcess,userno)); // 代码段2
        //sh文件生成
        String shName = remoteDirPath+projectName+"/"+"deploy_"+jarFileName+".sh";
        int jmxPort=0;
        String jmxsh="";
        int debuggerPort=0;
        String debuggersh="";
        if(isJMX){
            jmxPort=port+12311;
            jmxsh=" -Djava.rmi.server.hostname=1.15.232.156 -Dcom.sun.management.jmxremote.port="+jmxPort+" -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false ";
        }
        if(isDebugger){
            debuggerPort=port+12312;
            debuggersh=" -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address="+debuggerPort+" ";
        }
        String shContent = "SERVER_NAME="+jarName+" #服务jar包名称\n" +
                "pid=$(ps -ef|grep $SERVER_NAME|grep -v grep|awk '{print $2}');\n" +
                "if [  -n  \"$pid\"  ];  then\n" +
                "  kill  -9  $pid;\n" +
                "fi\n" +
                "nohup java -jar "+jmxsh+"  -Dspring.profiles.active=dev "+debuggersh+" $SERVER_NAME  >  rezhi.log &\n" +
                " \n";
        channelSftp.put(new ByteArrayInputStream(shContent.getBytes()), shName);
        JarServiceBean jarServiceBean = new JarServiceBean();
        jarServiceBean.setId(UUIDUtil.getUUID());
        jarServiceBean.setJar_name(jarFileName);
        jarServiceBean.setService_de(ms);
        jarServiceBean.setService_name(projectName);
        jarServiceBean.setJar_dir(remoteDirPath+projectName);
        jarServiceBean.setJar_path(dst);
        jarServiceBean.setPort(port);
        jarServiceBean.setRead_state(1);
        jarServiceBean.setJar_sh_path(shName);
        jarServiceBean.setVersion(version);
        jarServiceBean.setJmxPort(jmxPort);
        jarServiceBean.setDebuggerPort(debuggerPort);
        jarServiceMapper.insert(jarServiceBean);
        redisUtils.del("manager:all_jar");
        channelSftp.exit();
        channelSftp.quit();
    }


    @ApiMapping(value = "runjar", title = "执行jar包服务", description = "执行jar包服务",returnType=false)
    public ApiResponse runJar(String jarID) throws Exception{
        JarServiceBean jarServiceBean=jarServiceMapper.selectById(jarID);
        if(jarServiceBean==null){
            return ApiResponse.fail(500,"该ID无对应jar包");
        }else{
            SSHBean sshBean= new SSHBean();
            sshBean.sshRemoteLogin();
            SSHCache.sshMap.put(UUIDUtil.getUUID(),sshBean);
            ChannelExec channelExec = (ChannelExec) sshBean.getSession().openChannel("exec");
            String jarName=jarServiceBean.getJar_name();
            String shDir=jarServiceBean.getJar_dir();
            String shPath=jarServiceBean.getJar_sh_path();
            if(shPath==null){
                return ApiResponse.fail(501,"该jar包无对应部署脚本");
            }
            try {
                channelExec.setCommand("cd .. && cd "+shDir+" && sh deploy_"+jarName+".sh");
                channelExec.connect();
            } catch (JSchException e) {
                e.printStackTrace();
                return ApiResponse.fail(502,"部署失败,可能的原因是jar包损坏或者打包有问题");
            }  catch (Exception e) {
                e.printStackTrace();
                return ApiResponse.fail(502,"部署失败,可能的原因是jar包损坏或者打包有问题");
            } finally {
                if (channelExec != null) {
                    channelExec.disconnect();
                }
            }
            String processDataStream=getCommand("ps -ef|grep "+jarName+".jar|grep -v grep|awk '{print $2}'");
            if(processDataStream==null||"".equals(processDataStream)||"error".equals(processDataStream)){
                return ApiResponse.fail(502,"部署失败,可能的原因是jar包损坏或者打包有问题");
            }else{
                redisUtils.del("manager:last_jar_class_"+jarID);
                redisUtils.del("manager:all_jar");
                processDataStream=processDataStream.split(System.lineSeparator())[0];
                jarServiceBean.setPid(Integer.parseInt(processDataStream));
                jarServiceBean.setState(1);
                jarServiceBean.setJar_rezhi_path(shDir+"/rezhi.log");
                jarServiceMapper.updateById(jarServiceBean);
            }
            return ApiResponse.success("运行成功！");
        }
    }

    @ApiMapping(value = "gc", title = "强行gc", description = "通过jarID，执行垃圾回收")
    public void gc(String id) throws Exception {
        JarServiceBean jarServiceBean=jarServiceMapper.selectById(id);
        if(jarServiceBean==null){
            throw new RuntimeException("该ID无对应jar包");
        }else{
            if(jarServiceBean.getRead_state()==0){
                throw new RuntimeException("该服务只读！！！");
            }
            String processDataStream=getCommand("jcmd "+jarServiceBean.getPid()+" GC.run");
            if(processDataStream==null||"".equals(processDataStream)||"error".equals(processDataStream)){
                throw new RuntimeException("垃圾回收,可能的原因是jar包损坏或者服务有问题");
            }
            String[] jvms=processDataStream.split(System.lineSeparator());
            if(jvms.length<=1){
                throw new RuntimeException("垃圾回收失败,可能的原因是服务已终止");
            }
        }
    }

    @ApiMapping(value = "showJVM", title = "打印jvm参数", description = "通过jarID，打印jvm参数")
    public String[] showJVM(String id) throws Exception {
        JarServiceBean jarServiceBean=jarServiceMapper.selectById(id);
        if(jarServiceBean==null){
            throw new RuntimeException("该ID无对应jar包");
        }else{
            String processDataStream=getCommand("jcmd "+jarServiceBean.getPid()+" VM.command_line");
            if(processDataStream==null||"".equals(processDataStream)||"error".equals(processDataStream)){
                throw new RuntimeException("打印失败,可能的原因是jar包损坏或者打包有问题");
            }
            String[] jvms=processDataStream.split(System.lineSeparator());
            if(jvms.length<=1){
                throw new RuntimeException("打印失败,可能的原因是服务已终止");
            }
            return jvms;
        }
    }

    @ApiMapping(value = "exportHead", title = "导出堆栈信息", description = "通过jarID，导出堆栈信息")
    public void exportHead(String id,HttpServletResponse response) throws Exception {
        JarServiceBean jarServiceBean=jarServiceMapper.selectById(id);
        String uuid=UUIDUtil.getUUID();
        if(jarServiceBean==null){
            throw new RuntimeException("该ID无对应jar包");
        }else{
            String processDataStream=getCommand("jcmd "+jarServiceBean.getPid()+" GC.heap_dump "+jarServiceBean.getJar_dir()+"/"+jarServiceBean.getService_name()+"_heapdump.hprof",uuid);
            if(processDataStream==null||"".equals(processDataStream)||"error".equals(processDataStream)){
                throw new RuntimeException("导出失败,可能的原因是jarID有问题");
            }
            SSHBean sshBean= SSHCache.sshMap.get(uuid);
            Session session=sshBean.getSession();
            ChannelSftp channelSftp = (ChannelSftp)session.openChannel("sftp");
            channelSftp.connect();
            byte[] fileData = new byte[1024*128];
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            channelSftp.get(jarServiceBean.getJar_dir()+"/"+jarServiceBean.getService_name()+"_heapdump.hprof", baos);
            fileData = baos.toByteArray();
            // 设置响应头
            response.setContentType("application/multipart/form-data");
            response.setHeader("Content-Disposition", "attachment;filename="+jarServiceBean.getService_name()+"_heapdump.hprof");
            response.setContentLength(fileData.length);

            // 将字节数组写入响应
            try {
                ServletOutputStream outputStream = response.getOutputStream();
                outputStream.write(fileData);
                outputStream.flush();
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

            // 断开连接
            channelSftp.disconnect();
            session.disconnect();
        }
    }

    @ApiMapping(value = "showJMX", title = "showJMX", description = "showJMX")
    public Object showJMX(String jmxUrl) throws Exception {
        JMXConnector connector = null;
        try{
            JMXServiceURL url = new JMXServiceURL(jmxUrl);//service:jmx:rmi:///jndi/rmi://1.15.232.156:20398/jmxrmi
            connector = JMXConnectorFactory.connect(url);
            MBeanServerConnection mbs = connector.getMBeanServerConnection();
            ObjectName objName = new ObjectName("java.lang:type=Runtime");
            String propName = "SystemProperties";
            Object propValue = mbs.getAttribute(objName, propName);
            MemoryMXBean memoryMXBean = ManagementFactory.newPlatformMXBeanProxy(mbs, ManagementFactory.MEMORY_MXBEAN_NAME, MemoryMXBean.class);
            RuntimeMXBean runtimeMXBean = ManagementFactory.newPlatformMXBeanProxy(mbs, ManagementFactory.RUNTIME_MXBEAN_NAME, RuntimeMXBean.class);
            ThreadMXBean threadMXBean = ManagementFactory.newPlatformMXBeanProxy(mbs, ManagementFactory.THREAD_MXBEAN_NAME, ThreadMXBean.class);
            java.lang.management.OperatingSystemMXBean operatingSystemMXBean = ManagementFactory.newPlatformMXBeanProxy(mbs, ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME, OperatingSystemMXBean.class);
            String jvmName = runtimeMXBean.getName();
            System.out.println("pid:" + jvmName.split("@")[0]);
            return propValue;
        }catch (Exception ex){
            ex.printStackTrace();
        }finally {
            if(connector!=null){
                connector.close();
            }
            
        }
        return null;
    }


    @ApiMapping(value = "showJarClass", title = "打印jar的类", description = "通过jarID，打印jar的类")
    public String[] showJarClass(String id) throws Exception {
        JarServiceBean jarServiceBean=jarServiceMapper.selectById(id);
        if(jarServiceBean==null){
            throw new RuntimeException("该ID无对应jar包");
        }else{
            String processDataStream;
            if(redisUtils.hasKey("manager:last_jar_class_"+id)){
                processDataStream=redisUtils.get("manager:last_jar_class_"+id).toString();
            }else{
                processDataStream=getCommand("jcmd "+jarServiceBean.getPid()+" GC.class_histogram");
                redisUtils.set("manager:last_jar_class_"+id,processDataStream);
            }
            if(processDataStream==null||"".equals(processDataStream)||"error".equals(processDataStream)){
                throw new RuntimeException("打印失败,可能的原因是jar包损坏或者打包有问题");
            }
            redisUtils.set("manager:last_update_class",new Date());
            String[] jvms=processDataStream.split(System.lineSeparator());
            if(jvms.length<=1){
                throw new RuntimeException("打印失败,可能的原因是服务已终止");
            }
            return jvms;
        }
    }

    @ApiMapping(value = "removeJMXAndDebugger", title = "移除JMX监控和远程调试", description = "通过jarID，移除JMX监控和远程调试")
    public void removeJMXAndDebugger(String id) throws Exception {
        JarServiceBean jarServiceBean=jarServiceMapper.selectById(id);
        if(jarServiceBean==null){
            throw new RuntimeException("该ID无对应服务");
        }else{
            if(jarServiceBean.getRead_state()==0){
                throw new RuntimeException("该服务只读！！！");
            }
            if(jarServiceBean.getJmxPort()==0){
                throw new RuntimeException("该服务没有启用JMX监控和远程调试");
            }
            jarServiceBean.setJmxPort(0);
            jarServiceBean.setDebuggerPort(0);
            jarServiceMapper.updateById(jarServiceBean);
            redisUtils.del("manager:all_jar");
            String shName = jarServiceBean.getJar_sh_path();
            String shContent = "SERVER_NAME="+jarServiceBean.getJar_name()+".jar #服务jar包名称\n" +
                    "pid=$(ps -ef|grep $SERVER_NAME|grep -v grep|awk '{print $2}');\n" +
                    "if [  -n  \"$pid\"  ];  then\n" +
                    "  kill  -9  $pid;\n" +
                    "fi\n" +
                    "nohup java -jar -Dspring.profiles.active=dev $SERVER_NAME  >  rezhi.log &\n" +
                    " \n";
            SSHBean sshBean= new SSHBean();
            sshBean.sshRemoteLogin();
            Session sshSession=sshBean.getSession();
            SSHCache.sshMap.put(UUIDUtil.getUUID(),sshBean);
            ChannelSftp channelSftp = (ChannelSftp) sshSession.openChannel("sftp");
            channelSftp.connect();
            channelSftp.put(new ByteArrayInputStream(shContent.getBytes()), shName);
        }
    }

    @ApiMapping(value = "setJMXAndDebugger", title = "设置JMX监控和远程调试", description = "通过jarID，设置JMX监控和远程调试")
    public void setJMXAndDebugger(String id) throws Exception {
        JarServiceBean jarServiceBean=jarServiceMapper.selectById(id);
        if(jarServiceBean==null){
            throw new RuntimeException("该ID无对应服务");
        }else{
            if(jarServiceBean.getRead_state()==0){
                throw new RuntimeException("该服务只读！！！");
            }
            if(jarServiceBean.getJmxPort()!=0){
                throw new RuntimeException("该服务已设置JMX监控和远程调试");
            }
            String shName = jarServiceBean.getJar_sh_path();
            int jmxPort=0;
            String jmxsh="";
            int debuggerPort=0;
            String debuggersh="";
            int port=jarServiceBean.getPort();
            jmxPort=port+12311;
            jmxsh=" -Djava.rmi.server.hostname=1.15.232.156 -Dcom.sun.management.jmxremote.port="+jmxPort+" -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false ";
            debuggerPort=port+12312;
            debuggersh=" -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address="+debuggerPort+" ";
            String shContent = "SERVER_NAME="+jarServiceBean.getJar_name()+".jar #服务jar包名称\n" +
                    "pid=$(ps -ef|grep $SERVER_NAME|grep -v grep|awk '{print $2}');\n" +
                    "if [  -n  \"$pid\"  ];  then\n" +
                    "  kill  -9  $pid;\n" +
                    "fi\n" +
                    "nohup java -jar "+jmxsh+"  -Dspring.profiles.active=dev "+debuggersh+" $SERVER_NAME  >  rezhi.log &\n" +
                    " \n";
            jarServiceBean.setJmxPort(jmxPort);
            jarServiceBean.setDebuggerPort(debuggerPort);
            jarServiceMapper.updateById(jarServiceBean);
            redisUtils.del("manager:all_jar");
            SSHBean sshBean= new SSHBean();
            sshBean.sshRemoteLogin();
            Session sshSession=sshBean.getSession();
            SSHCache.sshMap.put(UUIDUtil.getUUID(),sshBean);
            ChannelSftp channelSftp = (ChannelSftp) sshSession.openChannel("sftp");
            channelSftp.connect();
            channelSftp.put(new ByteArrayInputStream(shContent.getBytes()), shName);
        }
    }

    @ApiMapping(value = "stopJVM", title = "停止java进程", description = "通过jarID，停止java进程,该方法不会返回任何数据")
    public void stopJVM(String id) throws Exception {
        JarServiceBean jarServiceBean=jarServiceMapper.selectById(id);
        if(jarServiceBean==null){
            throw new RuntimeException("该ID无对应jar包");
        }else{
            if(jarServiceBean.getRead_state()==0){
                throw new RuntimeException("该服务只读！！！");
            }
            redisUtils.del("manager:last_jar_class_"+id);
            redisUtils.del("manager:all_jar");
            getCommand("kill -s 9 "+jarServiceBean.getPid());
        }
    }

    @ApiMapping(value = "showlog", title = "打印日志", description = "通过jarID，打印日志")
    public String showlog(String id) throws Exception {
        JarServiceBean jarServiceBean=jarServiceMapper.selectById(id);
        if(jarServiceBean==null){
            throw new RuntimeException("该ID无对应日志");
        }else{
            String processDataStream=getCommand("cat " + jarServiceBean.getJar_rezhi_path());
            if(processDataStream==null||"".equals(processDataStream)||"error".equals(processDataStream)){
                throw new RuntimeException("打印失败,可能的原因是日志存在或者生成失败");
            }
            return processDataStream;
        }
    }


    @ApiMapping(value = "downloadJar", title = "下载日志", description = "通过jarID，下载日志")
    public void downloadJar(String id, HttpServletResponse response) throws Exception {
        JarServiceBean jarServiceBean=jarServiceMapper.selectById(id);
        if(jarServiceBean==null){
            throw new RuntimeException("该ID无对应日志");
        }else{
            SSHBean sshBean= new SSHBean();
            sshBean.sshRemoteLogin();
            SSHCache.sshMap.put(UUIDUtil.getUUID(),sshBean);
            Session session=sshBean.getSession();
            ChannelSftp channelSftp = (ChannelSftp)session.openChannel("sftp");
            channelSftp.connect();
            byte[] fileData = new byte[1024];
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            channelSftp.get(jarServiceBean.getJar_rezhi_path(), baos);
            fileData = baos.toByteArray();

            // 设置响应头
            response.setContentType("application/multipart/form-data");
            response.setHeader("Content-Disposition", "attachment;filename="+jarServiceBean.getService_name()+"_log.txt");
            response.setContentLength(fileData.length);

            // 将字节数组写入响应
            try {
                ServletOutputStream outputStream = response.getOutputStream();
                outputStream.write(fileData);
                outputStream.flush();
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

            // 断开连接
            channelSftp.disconnect();
            session.disconnect();
        }
    }

    @ApiMapping(value = "showlogss", title = "打印日志实时", description = "通过jarID，打印日志实时")
    public void showlogss(String id,String userno) throws Exception {
        JarServiceBean jarServiceBean=jarServiceMapper.selectById(id);
        if(jarServiceBean==null){
            throw new RuntimeException("该ID无对应日志");
        }else{
            InputStream in = null;
            ChannelExec channelExec = null;
            BufferedReader inputStreamReader = null;
            BufferedReader errInputStreamReader = null;
            try {
                SSHBean newSsh= new SSHBean();
                newSsh.sshRemoteLogin();
                String sessionId=UUIDUtil.getUUID();
                SSHCache.sshMap.put(sessionId,newSsh);
                webSocketProcess.sendCmdMessage(200,sessionId,"jar_log_session:"+sessionId,userno);
                Session sshSession=newSsh.getSession();
                channelExec = (ChannelExec) newSsh.getSession().openChannel("exec");
                //String command = "tail -" +count+ "f " +logPath;
                channelExec.setCommand("tail -0f " + jarServiceBean.getJar_rezhi_path());
                channelExec.setInputStream(null);
                ((ChannelExec)channelExec).setErrStream(System.err);
                channelExec.connect();  // 执行命令

                inputStreamReader = new BufferedReader(new InputStreamReader(channelExec.getInputStream()));
                errInputStreamReader = new BufferedReader(new InputStreamReader(channelExec.getErrStream()));
                String line = null;
                while ((line = inputStreamReader.readLine()) != null) {
                    if(!sshSession.isConnected()){
                        webSocketProcess.sendCmdMessage(501,"会话过期","jar_log_session_notConnected:"+sessionId,userno);
                        if (in != null) {
                            in.close();
                        }
                        if (channelExec != null) {
                            channelExec.disconnect();
                        }
                    }else{
                        webSocketProcess.sendCmdMessage(200,line,"jar_log_success:"+sessionId,userno);
                    }
                }
                String errLine = null;
                while ((errLine = errInputStreamReader.readLine()) != null) {
                    if(!sshSession.isConnected()){
                        webSocketProcess.sendCmdMessage(501,"会话过期","jar_log_session_notConnected:"+sessionId,userno);
                        if (in != null) {
                            in.close();
                        }
                        if (channelExec != null) {
                            channelExec.disconnect();
                        }
                    }else{
                        webSocketProcess.sendCmdMessage(500,errLine,"jar_log_fail:"+sessionId,userno);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (in != null) {
                    in.close();
                }
                if (channelExec != null) {
                    channelExec.disconnect();
                }
            }
        }
    }

    @Async
    public void insertLog(RequestInfo requestInfo) {
        logDao.insertLog(requestInfo);
    }

    /**
     * 对将要执行的linux的命令进行遍历
     * @param in
     * @return
     * @throws Exception
     */
    private String processDataStream(InputStream in) throws Exception {
        StringBuffer sb = new StringBuffer();
        BufferedReader br = new BufferedReader(new InputStreamReader(in));
        String result = "";
        try {
            while ((result = br.readLine()) != null) {
                sb.append(result).append(System.lineSeparator());
                // System.out.println(sb.toString());
            }
        } catch (Exception e) {
            throw new Exception("获取数据流失败: " + e);
        } finally {
            br.close();
        }
        return sb.toString();
    }

    /**
     * 带uuid执行指令
     * @param command
     * @param uuid
     * @return
     * @throws Exception
     */
    private String getCommand(String command,String uuid) throws Exception{
        InputStream in = null;// 输入流(读)
        ChannelExec newChannelExec = null;// 定义channel变量
        try {
            SSHBean newSsh= new SSHBean();
            newSsh.sshRemoteLogin();
            SSHCache.sshMap.put(uuid,newSsh);
            newChannelExec = (ChannelExec) newSsh.getSession().openChannel("exec");
            newChannelExec.setCommand(command);
            newChannelExec.connect();
            in = newChannelExec.getInputStream();
            String processDataStream = processDataStream(in);
            return processDataStream;
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (in != null) {
                in.close();
            }
            if (newChannelExec != null) {
                newChannelExec.disconnect();
            }
        }
    }

    private String getCommand(String command) throws Exception{
        return getCommand(command,UUIDUtil.getUUID());
    }
}

